from playwright.sync_api import sync_playwright
import time
import threading
import queue
import json
import os
from typing import List, Dict, Any


class BrowserManager(threading.Thread):
    """浏览器管理主线程（确保所有操作在同一个线程）"""

    def __init__(self):
        super().__init__(daemon=True)
        self.playwright = None
        self.browser = None
        self.context = None
        self.current_page = None
        self.user_data_dir = "./browser_data"
        self.command_queue = queue.Queue()  # 命令接收队列
        self.result_queue = queue.Queue()  # 结果返回队列
        self.stop_event = threading.Event()
        self.ready_event = threading.Event()
        self.start()

    def run(self):
        """浏览器主线程运行函数"""
        # 确保在目标线程中初始化Playwright
        self.playwright = sync_playwright().start()

        # 设置用户数据目录
        os.makedirs(self.user_data_dir, exist_ok=True)

        # 创建持久化浏览器上下文
        executable_path = "C:/Users/Administrator/AppData/Local/Google/Chrome/Bin/chrome.exe"
        self.browser = self.playwright.chromium.launch_persistent_context(
            user_data_dir=self.user_data_dir,
            headless=False,
            channel="chrome",
            executable_path=executable_path,
            args=["--start-maximized"],
            viewport={"width": 1920, "height": 1080},
            slow_mo=100  # 调试模式
        )

        # 获取当前页面
        self.current_page = self.browser.pages[0] if self.browser.pages else self.browser.new_page()

        # 标记浏览器准备就绪
        self.ready_event.set()
        print("[Browser Thread] 浏览器已就绪，等待命令...")

        # 主循环：处理命令
        while not self.stop_event.is_set():
            try:
                # 从队列中获取命令（非阻塞）
                command, args, kwargs = self.command_queue.get(timeout=1.0)

                print(command, args, kwargs)

                # 处理不同命令
                if command == "goto":
                    self._goto(*args, **kwargs)
                elif command == "login":
                    self._login(*args, **kwargs)
                elif command == "backgroud_crawl":
                    self._background_crawl(*args, **kwargs)
                elif command == "close":
                    self._close()
                    break

                # 标记任务完成
                self.command_queue.task_done()
            except queue.Empty:
                continue

    def wait_until_ready(self, timeout=30):
        """等待浏览器初始化完成"""
        if not self.ready_event.wait(timeout):
            raise TimeoutError("浏览器初始化超时")

    # ======= 命令处理函数 =======

    def _goto(self, url: str):
        """导航到页面"""
        print(f"[Browser Thread] 导航到: {url}")
        self.current_page.goto(url)
        self.result_queue.put(("navigation", url))
        print(f"[Browser Thread] 已发送导航完成事件: {url}")

    def _login(self, url: str):
        """用户登录流程"""
        print(f"[Browser Thread] 开始登录流程: {url}")
        self._goto(url)  # 发送 "navigation" 事件
        print("[Browser Thread] 等待用户登录...")
        self.result_queue.put(("login_waiting", "请手动登录网站"))  # 发送登录等待事件

        # 登录完成不需要额外发送消息
        # 只需改变浏览器状态即可
        print("[Browser Thread] 登录流程结束")

    def _background_crawl(self, url: str):
        """后台抓取页面 - 在当前页面抓取"""
        try:
            print(f"[Browser Thread] 开始抓取当前页面: {url}")

            # 确保页面已正确加载
            self.current_page.wait_for_load_state("networkidle", timeout=30000)

            # 滚动加载所有内容
            self.current_page.evaluate("""async () => {
                await new Promise(resolve => {
                    let totalHeight = 0;
                    const distance = 100;
                    const timer = setInterval(() => {
                        const scrollHeight = document.body.scrollHeight;
                        window.scrollBy(0, distance);
                        totalHeight += distance;

                        if(totalHeight >= scrollHeight){
                            clearInterval(timer);
                            resolve();
                        }
                    }, 100);
                });
            }""")

            # 等待所有内容加载完成
            self.current_page.wait_for_timeout(1000)

            # 获取页面内容
            content = self.current_page.content()
            print(f'[Browser Thread] 获取的页面内容长度: {len(content)}')

            print(f"[Browser Thread] 抓取完成: {url}")
            self.result_queue.put(("crawl", (url, content)))

        except Exception as e:
            print(f"[Browser Thread] 抓取出错: {str(e)}")
            self.result_queue.put(("error", (url, str(e))))

    def _close(self):
        """关闭浏览器"""
        print("[Browser Thread] 正在关闭浏览器...")
        if self.browser:
            self.browser.close()
        if self.playwright:
            self.playwright.stop()
        self.stop_event.set()
        print("[Browser Thread] 浏览器已关闭")

    # ======= 公共API =======

    def send_command(self, command: str, *args, **kwargs):
        """发送命令到浏览器线程"""
        self.command_queue.put((command, args, kwargs))

    def get_result(self, timeout=None):
        """获取处理结果"""
        return self.result_queue.get(timeout=timeout)


class PersistentBrowserManager:
    """主浏览器管理器"""

    def __init__(self):
        self.browser_thread = BrowserManager()
        self.browser_thread.wait_until_ready()
        self.user_data_dir = os.path.join(os.path.dirname(__file__), "data")
        print("[主线程] 浏览器管理器初始化完成")

    def user_login(self, url: str):
        """启动用户登录流程"""
        print("[主线程] 发送登录命令...")
        self.browser_thread.send_command("login", url)

        # 等待登录提示
        login_complete = False

        while not login_complete:
            event_type, data = self.browser_thread.get_result()
            print(f"[主线程] 收到事件: {event_type} - {data}")

            if event_type == "navigation":
                print(f"[主线程] 导航到登录页面: {data}")

            elif event_type == "login_waiting":
                print(f"[主线程] {data}")
                input("登录完成后按回车继续...")
                print("[主线程] 登录完成确认")
                login_complete = True

            elif event_type == "error":
                raise RuntimeError(f"登录失败: {data}")

        print("[主线程] 登录流程完成")

    def navigate(self, url: str):
        """导航到指定页面"""
        print(f"[主线程] 发送导航命令: {url}")
        self.browser_thread.send_command("goto", url)

        # 确保清空之前的消息
        navigation_complete = False
        navigation_url = None

        while not navigation_complete:
            event_type, data = self.browser_thread.get_result(timeout=10)
            print(f"[主线程] 收到导航相关事件: {event_type} - {data}")

            if event_type == "navigation":
                navigation_url = data
                print(f"[主线程] 导航到: {data}")
                navigation_complete = True
            elif event_type == "error":
                raise RuntimeError(f"导航失败: {data}")

        print(f"[主线程] 已成功导航到: {navigation_url}")
        return navigation_url

    def background_crawl(self, url: str):
        """开始后台抓取"""
        self.browser_thread.send_command("backgroud_crawl", url)

    def get_crawl_results(self, timeout=60):
        """获取抓取结果"""
        results = []

        # 等待任务完成
        start_time = time.time()
        while time.time() - start_time < timeout:
            try:
                event_type, data = self.browser_thread.get_result(timeout=1)
                if event_type == "crawl":
                    url, html = data
                    results.append((url, html))
                elif event_type == "error":
                    print(f"抓取出错: {data[0]} - {data[1]}")
            except queue.Empty:
                continue

        return results

    def crawl_page(self, url: str):
        """抓取单个页面并返回结果"""
        self.background_crawl(url)
        results = self.get_crawl_results()
        if not results:
            return None
        return results[0]

    def process_content(self, url: str, html: str):
        """处理内容"""
        print(f"处理页面内容: 内容长度为 {len(html)}")
        # 这里添加您的业务处理逻辑
        result = html
        return result

    def crawl_and_process(self, urls: List[str]):
        """抓取并处理多个页面"""
        # 启动所有抓取任务
        for url in urls:
            self.background_crawl(url)

        # 获取结果并处理
        processed_results = []
        while True:
            try:
                event_type, data = self.browser_thread.get_result(timeout=5)
                if event_type == "crawl":
                    url, html = data
                    print(f"抓取完成: {url}")
                    result = self.process_content(url, html)
                    processed_results.append(result)
                    print(f"处理完成: {url}")

                    # 保存结果
                    filename = f"result_{url.split('//')[-1].replace('/', '_')}.json"
                    os.makedirs(self.user_data_dir, exist_ok=True)
                    full_path = os.path.join(self.user_data_dir, filename)
                    with open(full_path, "w") as f:
                        # 简化为保存处理结果
                        json.dump({"result": result}, f, indent=2)

                elif event_type == "error":
                    url, error = data
                    print(f"抓取失败: {url} - {error}")

                # 检查是否所有任务完成
                error_count = sum(1 for m in self.browser_thread.result_queue.queue if m[0] == "error")
                if len(processed_results) + error_count >= len(urls):
                    break

            except queue.Empty:
                print("等待更多结果...")
                continue

        return processed_results

    def close(self):
        """关闭浏览器"""
        self.browser_thread.send_command("close")
        self.browser_thread.join(timeout=10)
        print("[主线程] 浏览器已关闭")


# 使用示例
if __name__ == "__main__":
    print("=" * 50)
    print("程序开始")
    print("=" * 50)

    browser_manager = PersistentBrowserManager()

    try:
        # 步骤1: 用户登录
        print(">> 步骤1: 用户登录")
        browser_manager.user_login("https://fxg.jinritemai.com/login/common")

        # 步骤2: 导航到主页面
        print("\n>> 步骤2: 导航到主页面")
        browser_manager.navigate("https://fxg.jinritemai.com/ffa/morder/order/list")

        # 步骤3: 定义要抓取的页面
        print("\n>> 步骤3: 定义抓取页面")
        urls_to_crawl = [
            "https://fxg.jinritemai.com/ffa/morder/order/list",
        ]

        # 步骤4: 抓取并处理页面
        print("\n>> 步骤4: 开始抓取并处理页面")
        results = browser_manager.crawl_and_process(urls_to_crawl)

        print('results', results)

        print(f"\n>> 成功处理 {len(results)} 个页面")

        # 步骤5: 保持浏览器打开，用户可以继续操作
        print("\n" + "=" * 50)
        print("浏览器保持打开状态...")
        print("输入 'exit' 结束程序")
        print("=" * 50)

        while True:
            cmd = input("> ")
            if cmd.strip().lower() == "exit":
                break

    except Exception as e:
        print(f"\n[错误] 程序异常: {str(e)}")
        import traceback

        traceback.print_exc()
    finally:
        print("\n>> 程序结束")
        browser_manager.close()
